/**
 * Class containing the always-cooperate strategy.
 * @author	081028AW
 */
public class StrategyEvolved extends Strategy
{
  /**
   * Encoding for a strategy.
   */

	//Define # of bits used for each property
	public static int optimismBitCount = 1;
	public static int forgivenessBitCount = 5;
	public static int penaltyBitCount = 5;
	public static int nicenessBitCount = 7;
	public static int totalBitCount = optimismBitCount + forgivenessBitCount + penaltyBitCount + nicenessBitCount;
	
	public int optimism; //Whether or not to cooperate on the first turn
	public int forgiveness; //How many consecutive defections we tolerate before defecting against them
	public int penalty; //When we "retaliate", how many times we will defect
	public int niceness;
	public double nicenessRate; //Given cooperating opponent, the % chance that we will cooperate
	public int defectCount = 0,  penaltyCount = 0;

	//0 = defect, 1 = cooperate
	
	public StrategyEvolved()
	{
		name = "Evolved Strategy";
	}  /* StrategyAlwaysDefect */

   
	public StrategyEvolved(int o, int f, int p, int n)
	{
		name = "Evolved Strategy";

		this.optimism = o;
		this.forgiveness = f;
		this.penalty = p;
		this.niceness = n;
		this.nicenessRate = (double) niceness/(Math.pow(2, StrategyEvolved.nicenessBitCount)-1);

        this.defectCount = 0;
        this.penaltyCount = 0;
        this.myLastMove = -1;
        this.opponentLastMove = 1;
	}
   
	public StrategyEvolved(String bitString)
	{
		this(-1, -1, -1, -1);

		if (bitString.length() == StrategyEvolved.totalBitCount)
		{
			String optimismString = bitString.substring(0, StrategyEvolved.optimismBitCount);
			bitString = bitString.substring(StrategyEvolved.optimismBitCount); //Cut off part of string just consumed
					
			String forgivenessString = bitString.substring(0, StrategyEvolved.forgivenessBitCount);
			bitString = bitString.substring(StrategyEvolved.forgivenessBitCount);

			String penaltyString = bitString.substring(0, StrategyEvolved.penaltyBitCount);
			bitString = bitString.substring(StrategyEvolved.penaltyBitCount);

			String nicenessString = bitString.substring(0, StrategyEvolved.nicenessBitCount);
			bitString = bitString.substring(StrategyEvolved.nicenessBitCount);

		   this.optimism = Integer.parseInt(optimismString, 2);
		   this.forgiveness = Integer.parseInt(forgivenessString, 2);
		   this.penalty = Integer.parseInt(penaltyString, 2);
		   this.niceness = Integer.parseInt(nicenessString, 2);
		   this.nicenessRate = (double) niceness/(Math.pow(2, StrategyEvolved.nicenessBitCount)-1);
		  // System.out.println(optimism +" "+ forgiveness +" "+ penalty +" "+ niceness);
		   
		}
	}
   
	public int nextMove()
	{
		if (myLastMove == -1){
			if(optimism == 1)
				return 1;
			else
				return 0;		  
		}
		if (opponentLastMove == 0)
		{
			defectCount++;
			if (defectCount >= forgiveness)
				penaltyCount = penalty;
		}
		if (penaltyCount>0)
		{
			penaltyCount--;
			return 0;
		}
		if (opponentLastMove == 1)
		{
			defectCount = 0;
			/*if (Math.random() > nicenessRate)
				return 0;
			else
				return 1;*/
		}
		if (Math.random() > nicenessRate)
			return 0;
		else
			return 1;
		//return 1;
	}
	
	public String getChromoValue()
	{
		String ret = "";
		
		ret += padLeft(Integer.toBinaryString(this.optimism), StrategyEvolved.optimismBitCount);
		ret += padLeft(Integer.toBinaryString(this.forgiveness), StrategyEvolved.forgivenessBitCount);
		ret += padLeft(Integer.toBinaryString(this.penalty), StrategyEvolved.penaltyBitCount);
		ret += padLeft(Integer.toBinaryString(this.niceness), StrategyEvolved.nicenessBitCount);
		
		return ret;
	}
	
	//Based off of http://www.rgagnon.com/javadetails/java-0448.html
	//pad with "0" to the left to the given length (n)
	public static String padLeft(String s, int n) {
		return String.format("%1$" + n + "s", s).replace(" ", "0");
	}
        
        public void printParameterSettings()
        {
            System.out.printf(
                      " O: " + optimism + "\n"
                    + " F: " + forgiveness + "\n"
                    + " P: " + penalty + "\n"
                    + " N: " + niceness + "\n"
                    + "NR: " + nicenessRate + "\n"
                    );
        }
        
        public void printParameterSettings(StrategyEvolved other)
        {
            System.out.printf(
                      " O: " + optimism     + "\t\t O: " + other.optimism + "\n"
                    + " F: " + forgiveness  + "\t\t F: " + other.forgiveness + "\n"
                    + " P: " + penalty      + "\t\t P: " + other.penalty +"\n"
                    + " N: " + niceness     + "\t\t N: " + other.niceness + "\n"
                    + "NR: " + nicenessRate + "\t\tNR: " + other.nicenessRate + "\n"
                    );
        }
        
        public static void printParameterSettings(String bitString)
        {
            StrategyEvolved strategy = new StrategyEvolved(bitString);
            strategy.printParameterSettings();
        }
        
        public static void printParameterSettings(String bitString1, String bitString2)
        {
            StrategyEvolved strategy1 = new StrategyEvolved(bitString1);
            StrategyEvolved strategy2 = new StrategyEvolved(bitString2);
            strategy1.printParameterSettings(strategy2);
        }
        
        public String getParameterSettings()
        {
            return " O: " + optimism + "\n"
                  + " F: " + forgiveness + "\n"
                  + " P: " + penalty + "\n"
                  + " N: " + niceness + "\n"
                  + "NR: " + nicenessRate + "\n";
        }
        
}  /* class StrategyAlwaysDefect */

